/** \file
    \brief Implementation of classes that interpret values in a string.

<pre>
               __________                                 ____  ___
    _____  __ _\______   \_____ _______  ______ __________\   \/  /
   /     \|  |  \     ___/\__  \\_  __ \/  ___// __ \_  __ \     / 
  |  Y Y  \  |  /    |     / __ \|  | \/\___ \\  ___/|  | \/     \
  |__|_|  /____/|____|    (____  /__|  /____  >\___  >__| /___/\  \
        \/                     \/           \/     \/           \_/

  muParserX - A C++ math parser library with array and string support
  Copyright 2010 Ingo Berg

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
  as published by the Free Software Foundation, either version 3 of 
  the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License
  along with this program.  If not, see http://www.gnu.org/licenses.
  </pre>
*/
#include "mpValReader.h"
#include "mpError.h"


MUP_NAMESPACE_START

  //------------------------------------------------------------------------------
  //
  //  Reader for floating point values
  //
  //------------------------------------------------------------------------------

  DblValReader::DblValReader()
    :IValueReader()
  {}

  //------------------------------------------------------------------------------
  DblValReader::~DblValReader()
  {}

  //------------------------------------------------------------------------------
  bool DblValReader::IsValue(const char_type * token,  Value &a_Val)
  {
    size_t tokenLength = strlen(token);
    assert( tokenLength > 0 );
    string_type stoken(token);
    stringstream_type stream(stoken);
    float_type fVal(0);
    std::streamoff iStart(0), iEnd(0);

    iStart = stream.tellg(); // Record position before reading
    stream >> fVal;
    iEnd = stream.tellg();   // Position after reading


    if (iEnd==-1)
      return false;
    
    int nonIntCharPos = stoken.find_first_not_of("0123456789");

    bool isImaginary = false;

    if( iEnd < tokenLength )
    {
      if(token[iEnd] == 'I'){
        isImaginary = true;
        iEnd++;
      }
    }

    if( iEnd == tokenLength )
    {
      // Finally i have to check if the next sign is the "I" for a imaginary unit
      // if so this is an imaginary value
      a_Val = isImaginary ? 
        cmplx_type(0.0, fVal) :
        cmplx_type(fVal, 0.0);
      if( !isImaginary && nonIntCharPos != std::string::npos && nonIntCharPos < iEnd){
        a_Val.MakeFloat();
      }
      return true;
    }else{
      return false;
    }
  }

//------------------------------------------------------------------------------
IValueReader* DblValReader::Clone(TokenReader *pTokenReader) const
{
  IValueReader *pReader = new DblValReader(*this);
  pReader->SetParent(pTokenReader);

  return pReader;
}

//------------------------------------------------------------------------------
//
//  Reader for boolean values
//
//------------------------------------------------------------------------------

  BoolValReader::BoolValReader()
:IValueReader()
{}

//------------------------------------------------------------------------------
BoolValReader::~BoolValReader()
{}

//------------------------------------------------------------------------------
bool BoolValReader::IsValue(const char_type *a_szExpr, Value &a_Val)
  {
    string_type sExpr(a_szExpr);

    if (sExpr == "true")
    {
      a_Val = true;
      return true;
    }
    else if (sExpr == "false")
    {
      a_Val = false;
      return true;
    }

    return false;
  }

  //------------------------------------------------------------------------------
  IValueReader* BoolValReader::Clone(TokenReader *pTokenReader) const
  {
    IValueReader *pReader = new BoolValReader(*this);
    pReader->SetParent(pTokenReader);

    return pReader;
  }

  //------------------------------------------------------------------------------
  //
  //  Reader for string values
  //
  //------------------------------------------------------------------------------

  StrValReader::StrValReader()
    :IValueReader()
  {}

  //------------------------------------------------------------------------------
  StrValReader::~StrValReader()
  {}

  //------------------------------------------------------------------------------
  bool StrValReader::IsValue(const char_type * token, Value &a_Val)
  {
   // do not need to do lexical analysis here any longer
   // that is all handled by the tokenizer
   size_t len = strlen(token);
   if( len > 2 ){
     if( token[0] == '"' && token[len-1] == '"')
     {
      char * buffer = new char[len];
      for(size_t i = 1; i < len-1; i++) buffer[i-1] = token[i];
      buffer[len-2] = 0;
      a_Val = string_type(buffer);
      return true;
     }
   }
   return false;
  }

  //------------------------------------------------------------------------------
  IValueReader* StrValReader::Clone(TokenReader *pTokenReader) const
  {
    IValueReader *pReader = new StrValReader(*this);
    pReader->SetParent(pTokenReader);

    return pReader;
  }
} // namespace mu
